/*
 * LDIR
 *
 * LDIR, a GPS cartography application built for Let's Do It Romania eco
 * campaign.
 * Copyright (C) 2010 Genera Software <office@generasoftware.com>
 *
 * http://generasoftware.com/
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <aknviewappui.h>
#include <eikappui.h>
#include <LDIR.rsg>
#include "LDIRMain.h"
#include "LDIRMainView.h"
#include "Settings.h"
#include "GPSPositionData.h"
#include "GPSNaviDecorator.h"
#include "gpsutils.h"
#include "WasteCache.h"
#include "LDIR.hrh"
#include "LDIRWaste.hrh"
#include "LDIRSettings.hrh"
#include "LDIRMain.hrh"
#include <aknlists.h>
#include <aknutils.h>
#include <akniconutils.h>
#include <akniconarray.h>
#include <AknsDrawUtils.h>
#include <gulicon.h>
#include <eikclbd.h>
#include <AknsBasicBackgroundControlContext.h>
#include <stringloader.h>
#include <LDIR.mbg>
_LIT(KListItemFormat, "%d\t%S\t%S\t");

/**
 * First phase of Symbian two-phase construction. Should not
 * contain any code that could leave.
 */
CLDIRMain::CLDIRMain()
    {
    }
/**
 * Destroy child controls.
 */
CLDIRMain::~CLDIRMain()
    {
    delete iBackground;
    }

void CLDIRMain::UpdatePositionL( const CGPSPositionData& aPositionData )
    {
    TBuf<64> buf;
    GPSUtils::AppendFormatLongitude( buf, aPositionData.Position().Longitude() );
    HBufC* text = StringLoader::LoadLC( LR_LONGITUDE, buf );
    iLongitude->SetTextL( *text );
    iLongitude->DrawDeferred();
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    buf.Zero();

    GPSUtils::AppendFormatLatitude( buf, aPositionData.Position().Latitude() );
    text = StringLoader::LoadLC( LR_LATITUDE, buf );
    iLatitude->SetTextL( *text );
    iLatitude->DrawDeferred();
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    buf.Zero();

    GPSUtils::AppendFormatSpeed( buf, aPositionData.HorizontalSpeed() );
    text = StringLoader::LoadLC( LR_SPEED, buf );
    iSpeed->SetTextL( *text );
    iSpeed->DrawDeferred();
    CleanupStack::PopAndDestroy( text );
    }

void CLDIRMain::SetSatInUseL( TInt aSatInUse )
    {
    iNaviGPS->SetSatInUseL( aSatInUse );
    iNaviGPS->DrawDeferred();
    }

void CLDIRMain::HandleSettingsChangedL()
    {
    CDesCArray* array = ( CDesCArray* ) iListBox->Model()->ItemTextArray();
    // List
    TBuf<128> entry;
    HBufC* text = StringLoader::LoadLC( LR_LIST_CACHE );
    HBufC* info = StringLoader::LoadLC( LR_ITEMS_IN_CACHE,
        CSettings::InstanceL().PendingUploadCache().Count() );
    entry.Format( KListItemFormat, 1, text, info );
    CleanupStack::PopAndDestroy( info );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    info = NULL;
    array->Delete( 1 );
    array->InsertL( 1, entry );

    // Upload
    text = StringLoader::LoadLC( LR_UPLOAD );
    info = StringLoader::LoadLC( LR_ITEMS_IN_CACHE,
        CSettings::InstanceL().PendingUploadCache().Count() );
    entry.Format( KListItemFormat, 2, text, info );
    CleanupStack::PopAndDestroy( info );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    info = NULL;
    array->Delete( 2 );
    array->InsertL( 2, entry );
    iListBox->HandleItemAdditionL();
    }

/**
 * Construct the control (first phase).
 *  Creates an instance and initializes it.
 *  Instance is not left on cleanup stack.
 * @param aRect bounding rectangle
 * @param aParent owning parent, or NULL
 * @param aCommandObserver command observer
 * @return initialized instance of CLDIRMain
 */
CLDIRMain* CLDIRMain::NewL( const TRect& aRect, const CCoeControl* aParent,
    MEikCommandObserver* aCommandObserver )
    {
    CLDIRMain* self = CLDIRMain::NewLC( aRect, aParent, aCommandObserver );
    CleanupStack::Pop( self );
    return self;
    }

/**
 * Construct the control (first phase).
 *  Creates an instance and initializes it.
 *  Instance is left on cleanup stack.
 * @param aRect The rectangle for this window
 * @param aParent owning parent, or NULL
 * @param aCommandObserver command observer
 * @return new instance of CLDIRMain
 */
CLDIRMain* CLDIRMain::NewLC( const TRect& aRect, const CCoeControl* aParent,
    MEikCommandObserver* aCommandObserver )
    {
    CLDIRMain* self = new ( ELeave ) CLDIRMain();
    CleanupStack::PushL( self );
    self->ConstructL( aRect, aParent, aCommandObserver );
    return self;
    }

/**
 * Construct the control (second phase).
 *  Creates a window to contain the controls and activates it.
 * @param aRect bounding rectangle
 * @param aCommandObserver command observer
 * @param aParent owning parent, or NULL
 */
void CLDIRMain::ConstructL( const TRect& aRect, const CCoeControl* aParent,
    MEikCommandObserver* aCommandObserver )
    {
    if ( aParent == NULL )
        {
        CreateWindowL();
        }
    else
        {
        SetContainerWindowL( *aParent );
        }
    iFocusControl = NULL;
    iCommandObserver = aCommandObserver;
    // support themes
    iBackground = CAknsBasicBackgroundControlContext::NewL(
        KAknsIIDQsnBgAreaMain, aRect, ETrue );
    InitializeControlsL();
    SetRect( aRect );
    ActivateL();
    }

/**
 *    Handle resizing of the container. This implementation will lay out
 *  full-sized controls like list boxes for any screen size, and will layout
 *  labels, editors, etc. to the size they were given in the UI designer.
 *  This code will need to be modified to adjust arbitrary controls to
 *  any screen size.
 */
void CLDIRMain::SizeChanged()
    {
    CCoeControl::SizeChanged();
    if ( iBackground )
        {
        // support themes
        delete iBackground;
        iBackground = NULL;
        iBackground = CAknsBasicBackgroundControlContext::NewL(
            KAknsIIDQsnBgAreaMain, Rect(), EFalse );
        }
    LayoutControls();
    }

TTypeUid::Ptr CLDIRMain::MopSupplyObject( TTypeUid aId )
    {
    // support themes
    return iBackground != NULL ? MAknsControlContext::SupplyMopObject( aId,
        iBackground ) : CCoeControl::MopSupplyObject( aId );
    }

void CLDIRMain::HandleListBoxEventL( CEikListBox* aListBox,
    TListBoxEvent anEventType )
    {
    if ( EEventItemClicked == anEventType || EEventEnterKeyPressed
        == anEventType )
        {
        TInt index = aListBox->CurrentItemIndex();
        switch ( index )
            {
            case 0:
                iCommandObserver->ProcessCommandL( ECmdAddWaste );
                break;
            case 1:
                iCommandObserver->ProcessCommandL( ECmdList );
                break;
            case 2:
                iCommandObserver->ProcessCommandL( ECmdUpload );
                break;
            case 3:
                iCommandObserver->ProcessCommandL( ECmdMapView );
                break;
            case 4:
                iCommandObserver->ProcessCommandL( ECmdSettings );
                break;
            default:
                break;
            };
        }
    }

/**
 * Layout components as specified in the UI Designer
 */
void CLDIRMain::LayoutControls()
    {
    TInt textHeight = iLongitude->MinimumSize().iHeight + 4;
    TSize textSize( Rect().Width() / 2, textHeight );
    iLongitude->SetExtent( TPoint( 0, 0 ), textSize );
    iLatitude->SetExtent( TPoint( 0, textHeight ), textSize );

    iNaviGPS->SetExtent( TPoint( Rect().Width() / 2, 0 ), textSize );

    iSpeed->SetExtent( TPoint( Rect().Width() / 2, textHeight ), textSize );
    if ( iListBox )
        iListBox->SetExtent( TPoint( 0, 2 * textHeight ), Rect().Size()
            - TSize( 0, 2 * textHeight ) );

    }

/**
 *    Handle key events.
 */
TKeyResponse CLDIRMain::OfferKeyEventL( const TKeyEvent& aKeyEvent,
    TEventCode aType )
    {
    if ( iFocusControl != NULL && iFocusControl->OfferKeyEventL( aKeyEvent,
        aType ) == EKeyWasConsumed )
        {
        return EKeyWasConsumed;
        }
    return CCoeControl::OfferKeyEventL( aKeyEvent, aType );
    }

/**
 *    Initialize each control upon creation.
 */
void CLDIRMain::InitializeControlsL()
    {
    InitComponentArrayL();
    iListBox = new ( ELeave ) CAknDoubleLargeStyleListBox;
    Components().AppendLC( iListBox );
    CleanupStack::Pop( iListBox );
    iListBox->ConstructL( this, EAknListBoxSelectionList );
    iListBox->SetContainerWindowL( *this );
    iListBox->SetMopParent( this );
    iListBox->CreateScrollBarFrameL( ETrue );
    iListBox->ScrollBarFrame()->SetScrollBarVisibilityL(
        CEikScrollBarFrame::EOn, CEikScrollBarFrame::EAuto );
    iListBox->SetListBoxObserver( this );
    iFocusControl = iListBox;

    // Status texts
    // get text color from skin
    TRgb textColor;
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    AknsUtils::GetCachedColor( skin, textColor, KAknsIIDQsnTextColors,
        EAknsCIQsnTextColorsCG6 );
    const CFont* font = LatinBold13();

    iLongitude = new ( ELeave ) CEikLabel;
    Components().AppendLC( iLongitude );
    HBufC* text = StringLoader::LoadLC( LR_LONGITUDE, KNullDesC );
    iLongitude->SetTextL( *text );
    iLongitude->OverrideColorL( EColorLabelText, textColor );
    iLongitude->SetFont( font );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    CleanupStack::Pop( iLongitude );

    iLatitude = new ( ELeave ) CEikLabel;
    Components().AppendLC( iLatitude );
    text = StringLoader::LoadLC( LR_LATITUDE, KNullDesC );
    iLatitude->SetTextL( *text );
    iLatitude->OverrideColorL( EColorLabelText, textColor );
    iLatitude->SetFont( font );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    CleanupStack::Pop( iLatitude );

    iNaviGPS = CGPSNaviDecorator::NewL();
    Components().AppendLC( iNaviGPS );
    CleanupStack::Pop( iNaviGPS );
    iNaviGPS->SetSearchingL();

    iSpeed = new ( ELeave ) CEikLabel;
    Components().AppendLC( iSpeed );
    text = StringLoader::LoadLC( LR_SPEED, KNullDesC );
    iSpeed->SetTextL( *text );
    iSpeed->OverrideColorL( EColorLabelText, textColor );
    iSpeed->SetFont( font );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    CleanupStack::Pop( iSpeed );

    SetIconArrayL();
    CreateListEntriesL();
    }

/**
 * Handle global resource changes, such as scalable UI or skin events (override)
 */
void CLDIRMain::HandleResourceChange( TInt aType )
    {
    CCoeControl::HandleResourceChange( aType );
    SetRect(
        iAvkonViewAppUi->View( TUid::Uid( ELDIRMainViewId ) )->ClientRect() );
    }

/**
 *    Draw container contents.
 */
void CLDIRMain::Draw( const TRect& aRect ) const
    {
    CWindowGc& gc = SystemGc();
    gc.Clear( aRect );
    // draw theme background
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    MAknsControlContext* cc = AknsDrawUtils::ControlContext( this );
    AknsDrawUtils::Background( skin, cc, this, gc, aRect );
    }

void CLDIRMain::SetIconArrayL()
    {
    CArrayPtr<CGulIcon>* iconList = new ( ELeave ) CAknIconArray( 2 );
    CleanupStack::PushL( iconList );

    CFbsBitmap* aBitmap;
    CFbsBitmap* aMask;
    CGulIcon* icon;
    TSize aSize;//I don't specify any custom size

    TFileName filename = CSettings::InstanceL().MifFile();

    AknIconUtils::CreateIconL( aBitmap, aMask, filename, EMbmLdirAdd_waste,
        EMbmLdirAdd_waste_mask );
    AknIconUtils::SetSize( aBitmap, aSize, EAspectRatioNotPreserved );

    icon = CGulIcon::NewL( aBitmap, aMask );
    CleanupStack::PushL( icon );
    icon->SetBitmapsOwnedExternally( EFalse );
    iconList->AppendL( icon );
    CleanupStack::Pop( icon );

    AknIconUtils::CreateIconL( aBitmap, aMask, filename, EMbmLdirList_waste,
        EMbmLdirList_waste_mask );
    AknIconUtils::SetSize( aBitmap, aSize, EAspectRatioNotPreserved );

    icon = CGulIcon::NewL( aBitmap, aMask );
    CleanupStack::PushL( icon );
    icon->SetBitmapsOwnedExternally( EFalse );
    iconList->AppendL( icon );
    CleanupStack::Pop( icon );

    AknIconUtils::CreateIconL( aBitmap, aMask, filename, EMbmLdirUpload,
        EMbmLdirUpload_mask );
    AknIconUtils::SetSize( aBitmap, aSize, EAspectRatioNotPreserved );

    icon = CGulIcon::NewL( aBitmap, aMask );
    CleanupStack::PushL( icon );
    icon->SetBitmapsOwnedExternally( EFalse );
    iconList->AppendL( icon );
    CleanupStack::Pop( icon );

    AknIconUtils::CreateIconL( aBitmap, aMask, filename, EMbmLdirMap,
        EMbmLdirMap_mask );
    AknIconUtils::SetSize( aBitmap, aSize, EAspectRatioNotPreserved );

    icon = CGulIcon::NewL( aBitmap, aMask );
    CleanupStack::PushL( icon );
    icon->SetBitmapsOwnedExternally( EFalse );
    iconList->AppendL( icon );
    CleanupStack::Pop( icon );

    AknIconUtils::CreateIconL( aBitmap, aMask, filename, EMbmLdirSettings,
        EMbmLdirSettings_mask );
    AknIconUtils::SetSize( aBitmap, aSize, EAspectRatioNotPreserved );

    icon = CGulIcon::NewL( aBitmap, aMask );
    CleanupStack::PushL( icon );
    icon->SetBitmapsOwnedExternally( EFalse );
    iconList->AppendL( icon );
    CleanupStack::Pop( icon );

    iListBox->ItemDrawer()->ColumnData()->SetIconArrayL( iconList );
    CleanupStack::Pop( iconList );
    }

void CLDIRMain::CreateListEntriesL()
    {
    TBuf<128> entry;
    CDesCArray* array = new ( ELeave ) CDesCArrayFlat( 4 );
    CleanupStack::PushL( array );
    // Add waste
    HBufC* text = StringLoader::LoadLC( LR_ADD_WASTE );
    entry.Format( KListItemFormat, 0, text, &KNullDesC );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    array->AppendL( entry );

    // List
    text = StringLoader::LoadLC( LR_LIST_CACHE );
    HBufC* info = StringLoader::LoadLC( LR_ITEMS_IN_CACHE,
        CSettings::InstanceL().PendingUploadCache().Count() );
    entry.Format( KListItemFormat, 1, text, info );
    CleanupStack::PopAndDestroy( info );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    info = NULL;
    array->AppendL( entry );

    // Upload
    text = StringLoader::LoadLC( LR_UPLOAD );
    info = StringLoader::LoadLC( LR_ITEMS_IN_CACHE,
        CSettings::InstanceL().PendingUploadCache().Count() );
    entry.Format( KListItemFormat, 2, text, info );
    CleanupStack::PopAndDestroy( info );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    info = NULL;
    array->AppendL( entry );

    // Map
    text = StringLoader::LoadLC( LR_MAP_WIEW );
    info = StringLoader::LoadLC( LR_UNIMPLEMENTED );
    entry.Format( KListItemFormat, 3, text, info );
    CleanupStack::PopAndDestroy( info );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    info = NULL;
    array->AppendL( entry );

    // Settings
    text = StringLoader::LoadLC( LR_SETTINGS );
    entry.Format( KListItemFormat, 4, text, &KNullDesC );
    CleanupStack::PopAndDestroy( text );
    text = NULL;
    array->AppendL( entry );

    // add array to list
    iListBox->Model()->SetItemTextArray( array );
    iListBox->Model()->SetOwnershipType( ELbmOwnsItemArray );
    CleanupStack::Pop( array );
    iListBox->HandleItemAdditionL();
    }

